package org.truenewx.tnxjee.repo.redis.serializer;

import java.nio.charset.StandardCharsets;
import javax.annotation.*;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.truenewx.tnxjee.core.util.ClassUtil;
import org.truenewx.tnxjee.core.util.JacksonUtil;

public class BaseTypeJackson2JsonRedisSerializer<T> implements RedisSerializer<T> {

    private Class<T> baseType;
    private ObjectMapper objectMapper;

    public BaseTypeJackson2JsonRedisSerializer(Class<T> baseType) {
        this.baseType = baseType;
        if (ClassUtil.isComplex(baseType)) {
            this.objectMapper = JacksonUtil.withClassProperty(JacksonUtil.copyDefaultMapper(),
                    clazz -> !this.baseType.equals(clazz) && this.baseType.isAssignableFrom(clazz));
        } else {
            this.objectMapper = JacksonUtil.DEFAULT_MAPPER;
        }
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        try {
            return this.objectMapper.writeValueAsBytes(t); // 此处内部固定使用UTF-8编码写入
        } catch (JsonProcessingException e) {
            throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
        }
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (ArrayUtils.isNotEmpty(bytes)) {
            try {
                String content = new String(bytes, StandardCharsets.UTF_8); // 固定使用UTF-8编码读取
                if (content.contains(JacksonUtil.CLASS_PROPERTY_KEY)) {
                    return this.objectMapper.readValue(content, new TypeReference<>() {
                    });
                } else {
                    return this.objectMapper.readValue(content, this.baseType);
                }
            } catch (JsonProcessingException e) {
                throw new SerializationException("Could not read JSON: " + e.getMessage(), e);
            }
        }
        return null;
    }

    @Override
    @Nonnull
    public Class<?> getTargetType() {
        return this.baseType;
    }

}
